package uni.androidgame.mapgeneration;

import android.graphics.Canvas;

import java.util.ArrayList;
import java.util.Collections;

import uni.androidgame.gameobjects.Tile;

public class Corridor
{
    private Room _room1;
    private Room _room2;
    private ArrayList<Tile> _tiles = new ArrayList<Tile>();

    public Corridor(Room room1, Room room2)
    {
        _room1 = room1;
        _room2 = room2;
    }

    public void connectRoomsVertical()
    {
        int door1X,door1Y,door2X,door2Y;
        if (_room1.isAboveOf(_room2)) //Room1 above room2
        {
            door1X = MapGenerator.getRandom(_room1.getX() + 1, _room1.getRightSide()-1);
            door1Y = _room1.getBottomSide();
            door2X = MapGenerator.getRandom(_room2.getX() + 1, _room2.getRightSide()-1);
            door2Y = _room2.getY();
            createVerticalLine(door1X, door1Y, door2X, door2Y);
            _room1.placeDoor(door1X,door1Y,_tiles.get(0));
            _room2.placeDoor(door2X,door2Y,_tiles.get(_tiles.size()-1));
        }
        else //if (room2.isAboveOf(room1)) //Room2 above room1
        {
            door1X = MapGenerator.getRandom(_room1.getX() + 1, _room1.getRightSide()-1);
            door1Y = _room1.getY();
            door2X = MapGenerator.getRandom(_room2.getX() + 1, _room2.getRightSide()-1);
            door2Y = _room2.getBottomSide();
            createVerticalLine(door2X, door2Y, door1X, door1Y);
            _room1.placeDoor(door1X,door1Y,_tiles.get(_tiles.size()-1));
            _room2.placeDoor(door2X,door2Y,_tiles.get(0));
        }

        addNeighbours();
    }
    public void connectRoomsHorizontal()
    {
        int door1X,door1Y,door2X,door2Y;

        if (_room1.isLeftOf(_room2)) //Room1 to the left of room2
        {
            door1X = _room1.getRightSide();
            door1Y = MapGenerator.getRandom(_room1.getY() + 1, _room1.getBottomSide() - 1);
            door2X = _room2.getX();
            door2Y = MapGenerator.getRandom(_room2.getY() + 1, _room2.getBottomSide() - 1);
            createHorizontalLine(door1X, door1Y, door2X, door2Y);
            _room1.placeDoor(door1X,door1Y,_tiles.get(0));
            _room2.placeDoor(door2X,door2Y,_tiles.get(_tiles.size() - 1));
        }
        else //if (room2.isLeftOf(room1)) //Room2 to the left of room1
        {
            door1X = _room1.getX();
            door1Y = MapGenerator.getRandom(_room1.getY() + 1, _room1.getBottomSide()-1);
            door2X = _room2.getRightSide();
            door2Y = MapGenerator.getRandom(_room2.getY() + 1, _room2.getBottomSide()-1);
            createHorizontalLine(door2X, door2Y, door1X, door1Y);
            _room1.placeDoor(door1X,door1Y,_tiles.get(_tiles.size()-1));
            _room2.placeDoor(door2X,door2Y,_tiles.get(0));
        }



        addNeighbours();
    }

    private void createHorizontalLine(int x0,int y0,int x1,int y1)
    {

        /*                   |....|
        |........|     jbbbbx|....|
        |........|xaaaaj     |....|
        |--------|
         */

        int junctionPoint = MapGenerator.getRandom(x0+1,x1-1);

        for(int a=x0+1;a<junctionPoint;a++)
        {
            _tiles.add(new Tile(Tile.Types.Floor, a, y0));
        }
        if(Math.abs(y0-y1)>0)//Multiple tiles in junction
        {
            int smallestY = Math.min(y0,y1);
            int biggestY = Math.max(y0,y1);
            ArrayList<Tile> junction = new ArrayList<Tile>();
                for(int y = smallestY;y<=biggestY;y++)
                {
                    junction.add(new Tile(Tile.Types.Floor, junctionPoint, y));
                }
            //To ensure that the path is in the correct order
            if(smallestY == y1)
            {
                Collections.reverse(junction);
            }
            _tiles.addAll(junction);
        }
        else//Only one in junction
        {
            _tiles.add(new Tile(Tile.Types.Floor, junctionPoint, y0));
        }

        for(int b=junctionPoint+1;b<x1;b++)
        {
            _tiles.add(new Tile(Tile.Types.Floor, b, y1));
        }
    }
    private void createVerticalLine(int x0, int y0, int x1, int y1)
    {

        /*
                  |....|
                  |....|
                  |....|
                    y0
                    a
                    a
             jjjjjjjj
             b
             b
             y1
        |........|
        |........|
         */

        int junctionPoint = MapGenerator.getRandom(y0+1,y1-1);

        for(int a=y0+1;a<junctionPoint;a++)
        {
            _tiles.add(new Tile(Tile.Types.Floor, x0, a));
        }

        if(Math.abs(x1-x0)>0)//Multiple in junction
        {
            int smallestX = Math.min(x0,x1);
            int biggestX = Math.max(x0,x1);
            ArrayList<Tile> junction = new ArrayList<Tile>();
            for(int x = smallestX;x<=biggestX;x++)
            {
                junction.add(new Tile(Tile.Types.Floor, x, junctionPoint));
            }
            if(smallestX == x1)
            {
                Collections.reverse(junction);
            }
            _tiles.addAll(junction);
        }
        else//Only one in junction point
        {
            _tiles.add(new Tile(Tile.Types.Floor, x0, junctionPoint));
        }

        for(int b=junctionPoint+1;b<y1;b++)
        {
            _tiles.add(new Tile(Tile.Types.Floor, x1, b));
        }
    }

    private void addNeighbours()
    {
        for(int i = 1;i<_tiles.size();i++)
        {
            _tiles.get(i-1).addNeighbour(_tiles.get(i));
            _tiles.get(i).addNeighbour(_tiles.get(i-1));
        }
    }

    public Tile getTile(int x, int y)
    {
        for(Tile t : _tiles)
        {
            if(t.getX()==x && t.getY() == y)
            {
                return t;
            }
        }
        return null;
    }

    public void draw(Canvas canvas)
    {
        for(Tile tile : _tiles)
        {
            tile.draw(canvas);
        }
    }
}
